import subprocess
import json
import os
import xmltodict
import sys
#from bs4 import BeautifulSoup

def get_next_level(path,username,password, force_accept_certificate):
    '''
        Execute query command and retrieve next level of the current folder. 
        Next level may include both folders and files.
    '''
    try:
        '''
        If there are errors during the call process, return error code 5100.
        '''
        if force_accept_certificate:
            xml_directories = (subprocess.check_output(["svn", "ls", "--depth=immediates", "--username="+username,"--password="+password,"--non-interactive","--trust-server-cert","--xml",path]))
        else:
            xml_directories = (subprocess.check_output(["svn", "ls", "--depth=immediates", "--username="+username,"--password="+password,"--non-interactive","--xml",path]))
    except subprocess.CalledProcessError:
        return "5100"

    try:
        #If it is not empty folder, there must be an "entry" tag.
        rtval = xml_to_object(xml_directories)['lists']['list']['entry']
    except KeyError:
        #Set rtval to empty list if it is an empty folder.
        rtval = []
    return rtval

def savefile(content, path, filename, username, password, hashtimestamp, commitmessage = False):
    '''
    Save content to local disk if no commitmessage supplied. If commitmessage is not false, then also commit to svn. 
    '''
    last_folder = path.split("/")[-1]

    timestamppath = (os.path.join(os.path.join(
        os.path.dirname(
            os.path.dirname(
                os.path.realpath(__file__))),'tmp'),hashtimestamp))

    file_localpath = os.path.join(os.path.join(timestamppath,last_folder),filename)

    with open(file_localpath, 'w') as f:
        f.write(content)

    if commitmessage:
        commit_reply = subprocess.Popen(["svn","commit","--non-interactive","--username="+username,"--password="+password, "-m",commitmessage], cwd=os.path.join(timestamppath,last_folder), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
        return commit_reply

def reset_change(path, filename, username, password, hashtimestamp):
    '''
    Reset local change of the file.
    '''
    last_folder = path.split("/")[-1]
    timestamppath = (os.path.join(os.path.join(
        os.path.dirname(
            os.path.dirname(
                os.path.realpath(__file__))),'tmp'),hashtimestamp))

    file_localpath = os.path.join(os.path.join(timestamppath,last_folder),filename)

    # Remove local file and re-checkout file from remote
    remove_file = subprocess.check_output(['rm', '-f', file_localpath])
    checkout_file_message = subprocess.Popen(["svn", "--username="+username,"--password="+password,"--non-interactive", "update", filename], cwd=os.path.join(timestamppath,last_folder))
    wait_till_finish = checkout_file_message.wait()

    # Read file line by line because javascript does not support multiline string literals
    with open(file_localpath, 'r') as f:
        file_content = f.readlines()

    rtval = ""
    for lines in file_content:
        rtval +=lines 
    return rtval

def checkout_file(path, filename,username, password, hashtimestamp, force_accept_certificate, newElement=False):
    '''
    Checkout the file from svn and return the file content.
    '''
    
    last_folder = path.split("/")[-1]
    timestamppath = (os.path.join(os.path.join(
        os.path.dirname(
            os.path.dirname(
                os.path.realpath(__file__))),'tmp'),hashtimestamp))

    if not os.path.exists(timestamppath):
        os.makedirs(timestamppath)

    if force_accept_certificate:
        # If repository does uses ssl certificate and require manual accept certificate
        checkout_dir_message = (subprocess.Popen(["svn", "co", "--username="+username,"--password="+password,"--non-interactive", "--depth=empty", "--trust-server-cert",path], cwd=timestamppath))
    else: 
        # Check out using normal certificate
        checkout_dir_message = (subprocess.Popen(["svn", "co", "--username="+username,"--password="+password,"--non-interactive", "--depth=empty", path], cwd=timestamppath))
    wait_till_finish = checkout_dir_message.wait()

    if not newElement:
        checkout_file_message = subprocess.Popen(["svn", "--username="+username,"--password="+password,"--non-interactive", "update", filename], cwd=os.path.join(timestamppath,last_folder))
        # Wait until finish so that when reading the file it would not say IOError
        wait_till_finish = checkout_file_message.wait()
        file_localpath = os.path.join(os.path.join(timestamppath,last_folder),filename)
        with open(file_localpath, 'r') as f:
            file_content = f.readlines()

        rtval = ""
        for lines in file_content:
            rtval +=lines 
        return rtval
    else:
        '''
        If newElement is set to be an object, that means this function is being called to create a new file/folder.
        '''
        if force_accept_certificate:
            # If repository does uses ssl certificate and require manual accept certificate
            checkout_dir_message = (subprocess.Popen(["svn", "co", "--username="+username,"--password="+password,"--non-interactive", "--depth=empty", "--trust-server-cert",os.path.join(path, filename)], cwd=timestamppath))
        else: 
            # Check out using normal certificate
            checkout_dir_message = (subprocess.Popen(["svn", "co", "--username="+username,"--password="+password,"--non-interactive", "--depth=empty", os.path.join(path, filename)], cwd=timestamppath))
        wait_till_finish = checkout_dir_message.wait()

        if filename:
            new_curr_path = os.path.join(timestamppath,filename)
        else:
            new_curr_path = os.path.join(timestamppath,last_folder)

        if newElement['type']=='File':
            create_new_file_message = subprocess.Popen(["touch", newElement['name']], cwd=new_curr_path)
            add_new_file_message = subprocess.Popen(["svn", "add",newElement['name']], cwd=new_curr_path)
            add_new_file_message.wait()
            commit_new_folder_message = subprocess.Popen(["svn", "commit", "--non-interactive", "--username="+username,"--password="+password, "-m", "new file"+newElement['name']+"added"], cwd=new_curr_path)
            commit_new_folder_message.wait()
        else:
            if newElement['type'] == 'Folder':
                create_new_folder_message = subprocess.Popen(["mkdir", newElement['name']], cwd=new_curr_path)
                add_new_folder_message = subprocess.Popen(["svn", "add",newElement['name']], cwd=new_curr_path)
                add_new_folder_message.wait()
                commit_new_folder_message = subprocess.Popen(["svn", "commit", "--non-interactive", "--username="+username,"--password="+password, "-m", "new folder"+newElement['name']+"added"], cwd=new_curr_path)
                commit_new_folder_message.wait()
        return "OK"
def xml_to_object(xml_string):
    '''
        Convert XML string to xml object, more specifically an OrderedList object.
    '''
    return xmltodict.parse(xml_string)